import { getVersion, setVersion } from '@/utils/storage'
import mitt from 'mitt'
import type { ShowDirectoryPicker } from '@/types/window.d'
import { i18n } from '@/language'

interface StorageProps {
  set: <T>(name: string, data: T) => void
  get: <T>(name: string) => T
  clear: () => void
  remove: (name: string) => void
}

export const Local: StorageProps = {
  set: <T>(name: string, data: T): void => {
    window.localStorage.setItem(name, JSON.stringify(data))
  },
  get: <T>(name: string): T => {
    return JSON.parse(window.localStorage.getItem(name) as string)
  },
  clear: (): void => {
    window.localStorage.clear()
  },
  remove: (name: string): void => {
    window.localStorage.removeItem(name)
  }
}

export const Session: StorageProps = {
  set: <T>(name: string, data: T): void => {
    window.sessionStorage.setItem(name, JSON.stringify(data))
  },
  get: <T>(name: string): T => {
    return JSON.parse(window.sessionStorage.getItem(name) as string)
  },
  clear: (): void => {
    window.sessionStorage.clear()
  },
  remove: (name: string): void => {
    window.sessionStorage.removeItem(name)
  }
}

export const sleep = (delay: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, delay))

// 系统栏事件监听
export const trayMitt = mitt<{ trayClick: { appId: string; taskId: string } }>()

// 窗口通信
export const browserChannel = new BroadcastChannel('browserChannel')

const _getZIndex = () => {
  let zIndex = 2000
  return () => zIndex++
}

/** 获取zIndex层级
 */
export const getZIndex = _getZIndex()

/** 时间格式化
 * @param {String} type 转时间方式  YYYY=年2019 YY=年19 MM=月 DD=天 hh:时 mm:分 ss:秒
 * @param {Date} val
 * @return {String} 格式换时间
 * */
export const dateFormat = (type: 'year' | 'month' | 'day' | string, val?: Date | string | number): string => {
  let date: Date = new Date()
  if (val) date = new Date(val)
  const YYYY = String(date.getFullYear())
  const YY = String(date.getFullYear()).slice(2, 4)
  const m = date.getMonth() + 1
  const MM = m > 9 ? String(m) : `0${m}`
  const M = String(m)
  const d = date.getDate()
  const DD = d > 9 ? String(d) : `0${d}`
  const D = String(d)
  const h = date.getHours()
  const hh = h > 9 ? String(h) : `0${h}`
  const $m = date.getMinutes()
  const mm = $m > 9 ? String($m) : `0${$m}`
  const s = date.getSeconds()
  const ss = s > 9 ? String(s) : `0${s}`
  const obj: {
    [key: string]: string
  } = {
    YYYY,
    YY,
    MM,
    M,
    DD,
    D,
    hh,
    h: String(h),
    mm,
    m: String($m),
    ss,
    s: String(s)
  }
  if (type === 'year') return YYYY
  if (type === 'month') return `${YYYY}-${MM}`
  if (type === 'day') return `${YYYY}-${MM}-${DD}`
  return type.replace(/(YYYY)|(YY)|(MM)|(M)|(DD)|(D)|(hh)|(h)|(mm)|(m)|(ss)|(s)/g, (key: string) => obj[key])
}

/**
 * 星期时间
 */
export const weekFormat = (val: Date | string | number): string => {
  return i18n.global.t(`default.week${new Date(val).getDay()}`)
}

/** 时间数值格式化
 * @param time
 */
export const timeFormat = (time: number): string => {
  const sec = time % 60
  const s = sec < 10 ? `0${sec}` : sec
  const min = Math.floor(time / 60) % 60
  const m = min < 10 ? `0${min}` : min
  const hour = Math.floor(time / 60 / 60) % 60
  const h = hour < 10 ? `0${hour}` : hour
  if (hour > 0) return `${h}:${m}:${s}`
  return `${m}:${s}`
}

/** 时间转数字
 * @param time
 */
export const timeToNumber = (time: string): number => {
  const arr = time.split(':')
  if (arr.length === 2) return Number(arr[0]) * 60 + Number(arr[1])
  if (arr.length === 3) return Number(arr[0]) * 60 * 60 + Number(arr[1]) * 60 + Number(arr[2])
  return 0
}

/** 文件大小格式化
 * @param size
 */
export const sizeFormat = (size: number): string => {
  const arr = ['B', 'KB', 'MB', 'GB', 'TB']
  let n = 0
  while (size >= 1024) {
    size = size / 1024
    n++
  }
  return `${size.toFixed(2)} ${arr[n]}`
}

/** 动态获取图片地址
 * @param url
 */
export const getImageUrl = (url: string): string => new URL(`../assets/images/${url}`, import.meta.url).href

/** 骇客技术添加css样式
 * @param style style名
 */
export const prefixStyle = (style: string): string | number => {
  const vendor = (() => {
    const transformName = {
      webkit: 'webkitTransform',
      Moz: 'MozTransform',
      O: 'OTransform',
      ms: 'msTransform',
      standard: 'transform'
    }
    for (const key in transformName) {
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      const domKey = document.createElement('div').style[transformName[key]]
      if (domKey !== undefined) return key
    }
    return false
  })()
  if (!vendor) return ''
  if (vendor === 'standard') return style
  return vendor + style.charAt(0).toUpperCase() + style.substr(1)
}

/** 随机字符
 * @param num 随机字符个数
 * @param text 前置字符串
 */
export const randomWord = (num: number, text: string = ''): string => {
  const arr = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
  return Array.from(new Array(num)).reduce((a: string) => {
    const random = Math.floor((arr.length - 1) * Math.random())
    return a + arr[random]
  }, text)
}

/** 获取聊天相差时间
 * @param date
 */
export const getChatDisDate = (date: string | Date): string => {
  const disDate = new Date(date).getTime()
  const today = new Date(new Date().setHours(0, 0, 0, 0)).getTime()
  const yesterday = new Date(new Date().setHours(0, 0, 0, 0) - 1000 * 60 * 60 * 24).getTime()
  if (disDate >= today) {
    return dateFormat('hh:mm', date)
  } else if (disDate >= yesterday) {
    return '昨天'
  } else {
    return dateFormat('YY年M月D', date)
  }
}

/** 文字排序
 * @param x
 * @param y
 */
export const sortName = (x: string, y: string): number => {
  const reg = /[a-zA-Z0-9]/
  if (reg.test(x) || reg.test(y)) {
    if (x > y) return 1
    if (x < y) return -1
    return 0
  }
  return x.localeCompare(y)
}

const isUpdateVersion = (val: string, old: string): boolean => {
  if (!val || !old) return false
  const valArr: number[] = val.split('.').map((item) => Number(item))
  const oldArr: number[] = old.split('.').map((item) => Number(item))
  if (valArr[0] > oldArr[0]) return true
  if (valArr[0] < oldArr[0]) return false
  if (valArr[1] > oldArr[1]) return true
  if (valArr[1] < oldArr[1]) return false
  if (valArr[2] > oldArr[2]) return true
  if (valArr[2] < oldArr[2]) return false
  if (valArr[3] > oldArr[3]) return true
  if (valArr[3] < oldArr[3]) return false
  return false
}

/** 是否需要更新数据
 * @param version
 */
export const isUpdate = (version: string): void => {
  const oldVersion = getVersion()
  if (!oldVersion) {
    setVersion(version)
  } else {
    if (isUpdateVersion(version, oldVersion)) {
      Local.clear()
      Session.clear()
      location.reload()
    }
  }
}

/** 全屏 */
export const openFullscreen = (dom: HTMLElement = document.body) => {
  try {
    dom.requestFullscreen && dom.requestFullscreen()
  } catch (e) {
    throw new Error('当前浏览器不支持全屏使用')
  }
}

/** 退出全屏 */
export const exitFullscreen = () => {
  document.exitFullscreen && document.exitFullscreen()
}

/** 获取文件夹内容
 * @param data
 * @param path
 */
export const getDirectoryPickerTree = async (data: any, path: string = ''): Promise<ShowDirectoryPicker> => {
  data.id = randomWord(20)
  data.path = `${path ? path + '/' : ''}${data.name}`
  if (data.kind === 'file') return data
  const item = await data.entries()
  const dirs = []
  const files = []
  for await (const itemElement of item) {
    const child = await getDirectoryPickerTree(itemElement[1], data.path)
    child.kind === 'directory' ? dirs.push(child) : files.push(child)
  }
  data.children = [...dirs.sort((a, b) => sortName(a.name, b.name)), ...files.sort((a, b) => sortName(a.name, b.name))]
  return data
}

/** 获取文件名的后缀名
 * @param name
 */
export const getFileType = (name: string): string => {
  const arr = name.split('.')
  return arr[arr.length - 1].toLowerCase()
}
/** 获取文件名的后缀名 并转为office类型
 * @param name
 */
export const getFileTypeToOffice = (name: string): string => {
  const type = getFileType(name)
  switch (type) {
    case 'docx':
    case 'doc':
      return 'word'
    case 'xls':
    case 'xlsx':
      return 'excel'
    default:
      return type
  }
}

/** 获取文件内容
 * @param file
 * @param type
 */
export const readFile = (file: File, type: 'toText' | 'toBuffer' | 'toBase64' = 'toText'): Promise<string> => {
  return new Promise((resolve) => {
    const render = new FileReader()
    type === 'toText'
      ? render.readAsText(file, 'utf-8')
      : type === 'toBase64'
        ? render.readAsDataURL(file)
        : render.readAsArrayBuffer(file)
    render.onload = (ev) => {
      resolve(ev.target!.result as string)
    }
  })
}

/** 选择文件
 * @param data
 */
export const selectFile = (data: { accept: string }): Promise<FileList> => {
  return new Promise((resolve) => {
    const input = document.createElement('input') as HTMLInputElement
    input.type = 'file'
    input.accept = data.accept
    input.click()
    const change = (ev: Event) => {
      input.remove()
      input.removeEventListener('change', change)
      const files = (ev.target as HTMLInputElement).files
      if (files && files.length) resolve(files)
    }
    input.addEventListener('change', change)
  })
}

/** 选择颜色 */
export const selectColor = (): Promise<string> => {
  return new Promise((resolve) => {
    const input = document.createElement('input') as HTMLInputElement
    input.type = 'color'
    input.click()
    const change = (ev: Event) => {
      input.remove()
      input.removeEventListener('change', change)
      const value = (ev.target as HTMLInputElement).value
      if (value) resolve(value)
    }
    input.addEventListener('change', change)
  })
}

export const getWordName = (num: number): string => {
  num = num - 1
  let text = ''
  const arr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')
  const len = arr.length - 1
  if (num > len) {
    text += arr[Math.floor(num / len) - 1] + getWordName(num - len)
  } else {
    text += arr[num]
  }
  return text
}
